#include "../Interfaces/InterfazAdministrador.h"
#include <limits>
#include <sstream>

using namespace Interfaces;
using namespace Encriptacion;
using namespace ABM;

InterfazAdministrador::InterfazAdministrador() {
}

void InterfazAdministrador::menuPrincipal() {

	if (this->menuPantallaLogin())
		this->menuAdministrador();

}

bool InterfazAdministrador::menuPantallaLogin() {
	int intentosFallidos = 0;
	bool loginOK = false;
	do {
		string contrasenia;
		system("clear");
		cout << "Menu Login Administrador: " << endl;
		cout << endl;
		cout << "Usuario: ";
		cin >> this->usuario;
		cout << "Contraseña: ";
		cin >> contrasenia;
		cout << " " << endl;
		if (!this->validarUsuarioYContraseniaAdmin(this->usuario, contrasenia)) {
			cout << endl;
			cout << "Usuario/clave u opcion Incorrecta! Presione una tecla para continuar" << endl;
			cin.ignore();
			getchar();
			loginOK = false;
			intentosFallidos++;
		} else {
			loginOK = true;
			break;
		}
	} while (intentosFallidos < 3);
	return loginOK;
}

void InterfazAdministrador::menuAdministrador() {
	bool fin = false;

	while (!fin) {
		system("clear");
		int opcionAdm = 0;
		cout << "Menu Administrador: " << endl;
		cout << "      0- ABM Administrador" << endl;
		cout << "      1- ABM Votante" << endl;
		cout << "      2- ABM Distrito" << endl;
		cout << "      3- ABM Cargo" << endl;
		cout << "      4- ABM Eleccion" << endl;
		cout << "      5- ABM Candidato" << endl;
		cout << "      6- ABM Lista" << endl;
		cout << "      7- Ver Reportes" << endl;
		cout << "      8- Ver Logs" << endl;
		cout << "      9- Carga Masiva de datos" << endl;
		cout << "      10- Generar votaciones automáticas" << endl;
		cout << "      11- Encriptar archivo con RSA" << endl;
		cout << "      12- Desencriptar archivo con RSA" << endl;
		cout << "      13- Ataque Kasiski " << endl;
		cout << "      14- Ataque a RSA " << endl;
		cout << "      15- Vigenere" << endl;
		cout << "      16- Cerrar Sesion de: " << this->usuario << endl;
		cout << endl;

		cout << "Elija la opcion: ";
		cin >> opcionAdm;
		cin.ignore();
		cout << endl;

		switch (opcionAdm) {
		case (0):
			this->menuABMAdministrador();
			break;
		case (1):
			this->menuABMVotante();
			break;
		case (2):
			this->menuABMDistrito();
			break;
		case (3):
			this->menuABMCargo();
			break;
		case (4):
			this->menuABMEleccion();
			break;
		case (5):
			this->menuABMCandidato();
			break;
		case (6):
			this->menuABMLista();
			break;
		case (7):
			this->menuReportes();
			break;
		case (8):
			this->menuLogs();
			break;
		case (9):
			this->altaMasivaDatos();
			break;
		case (10):
			this->menuVotantesAutomaticos();
			break;
		case (11):
			this->menuEncriptarArchivo();
			break;
		case (12):
			this->menuDesencriptarArchivo();
			break;
		case (13):
			this->menuAtaqueKasiski();
			break;
		case (14):
			this->menuAtaqueRSA();
			break;
		case (15):
			this->menuVigenere();
			break;
		case (16):
			fin = true;
			break;
		default: {
			cout << "Opcion Incorrecta! Presione cualquier tecla para volver al Menu" << endl;
			cin.ignore();
			getchar();
		}
		}

	}

}

void InterfazAdministrador::menuABMAdministrador() {
	IAbm* admin = new AdministradorABM();
	admin->menu();
	delete admin;
}

void InterfazAdministrador::menuABMVotante() {
	IAbm* votante = new VotanteABM();
	votante->menu();
	delete votante;
}

void InterfazAdministrador::menuABMDistrito() {
	IAbm* distrito = new DistritoABM();
	distrito->menu();
	delete distrito;
}

void InterfazAdministrador::menuABMEleccion() {
	IAbm* eleccion = new EleccionABM();
	eleccion->menu();
	delete eleccion;
}

void InterfazAdministrador::menuABMCandidato() {
	IAbm* candidato = new CandidatoABM();
	candidato->menu();
	delete candidato;
}

void InterfazAdministrador::menuABMLista() {
	IAbm* lista = new ListaABM();
	lista->menu();
	delete lista;
}

void InterfazAdministrador::menuABMCargo() {
	IAbm* cargo = new CargoABM();
	cargo->menu();
	delete cargo;
}

void InterfazAdministrador::menuReporteKasiski() {
	bool fin = false;
	int opcion = 0;
	while (!fin) {
		system("clear");

		cout << "Menu Reportes Kasiski: " << endl;
		cout << "      1- Encriptar Reporte por Distrito " << endl;
		cout << "      2- Encriptar Reporte por Lista" << endl;
		cout << "      3- Encriptar Reporte por Eleccion" << endl;
		cout << "      4- Volver" << endl;
		cout << "Elija la opcion: ";
		cin >> opcion;
		cout << endl;

		//		Configuracion* config = Configuracion::getInstancia();
		//		string path = config->getPathReportesKasiski();
		string path;
		switch (opcion) {
		case (1):
			path = "reportePorDistrito.txt";
			break;
		case (2):
			path = "reportePorLista.txt";
			break;
		case (3):
			path = "reportePorEleccion.txt";
			break;
		case (4):
			opcion = 0;
			fin = true;
			break;
		default: {
			cout << "Opcion Incorrecta! Presione cualquier tecla para volver al Menu" << endl;
			getchar();
			opcion = 0;
			break;
		}
		}
		if (opcion != 0) {
			cout << endl;
			string claveParaEncriptar;
			cout << "Ingrese la clave para la Encriptacion: ";
			cin >> claveParaEncriptar;
			Vigenere* vigenere = new Vigenere(claveParaEncriptar);
			vigenere->generarArchivoEncriptado(path, opcion);
			string opcionDesencripta;
			delete vigenere;
			cout << "El reporte se encripto correctamente" << endl;
			getchar();
		}
	}
	cout << "Presione ENTER para continuar..." << endl;
	getchar();
}

void InterfazAdministrador::menuAtaqueKasiski() {
	bool fin = false;
	int opcion = 0;
	while (!fin) {
		int eligio = -1;
		system("clear");
		cout << "Elija el archivo Encriptado para atacar: " << endl;
		cout << "      1- Encriptar reporte Kasiski" << endl;
		cout << "      2- Ataque Reporte por Distrito " << endl;
		cout << "      3- Ataque Reporte por Lista" << endl;
		cout << "      4- Ataque Reporte por Eleccion" << endl;
		cout << "      5- Volver" << endl;
		cout << "Elija la opcion: ";
		cin >> opcion;
		cout << endl;

		Configuracion* config = Configuracion::getInstancia();
		string pathDesencriptacion = config->getPathEncriptado();
		string nombreDiccionarioKasiski;

		if (opcion >= 1 && opcion <= 4) {
			cout << " ________________________________________________________________________ " << endl;
			cout << "|                                                                        |" << endl;
			cout << "|NOTA: El Ataque Funciona con Reportes Similares a los generados por     |" << endl;
			cout << "|      el programa. Estos reportes se encuentran la carpeta /TP0         |" << endl;
			cout << "|________________________________________________________________________|" << endl;
			cout << "Presione una tecla para continuar..." << endl;
			getchar();
		}
		getchar();

		switch (opcion) {
		case (1):
			this->menuReporteKasiski();
			opcion = 0;
			getchar();
			break;
		case (2):
			pathDesencriptacion += "reportePorDistritoEncriptado.txt";
			nombreDiccionarioKasiski = "diccionarioKasiskiReporteDistrito.txt";
			break;
		case (3):
			pathDesencriptacion += "reportePorListaEncriptado.txt";
			nombreDiccionarioKasiski = "diccionarioKasiskiReporteLista.txt";
			break;
		case (4):
			pathDesencriptacion += "reportePorEleccionEncriptado.txt";
			nombreDiccionarioKasiski = "diccionarioKasiskiReporteEleccion.txt";
			break;
		case (5):
			opcion = 0;
			fin = true;
			break;
		default: {
			cout << "Opcion Incorrecta! Presione cualquier tecla para volver al Menu" << endl;
			getchar();
			opcion = 0;
			break;
		}
		}

		if (opcion != 0) {
			cout << endl;
			fstream encriptado;
			encriptado.open(pathDesencriptacion.c_str(), ios::in);
			if (encriptado.good()) {
				Kasiski* kasiski = new Kasiski(pathDesencriptacion, nombreDiccionarioKasiski);
				vector<ocurrencia> clavesPosibles = kasiski->ataqueKasiski();
				stringstream change;
				string claveEnString;
				cout << "Claves Posibles" << endl;
				cout << "===============" << endl;
				/* Imprimo claves posibles */
				for (unsigned int i = 0; i < clavesPosibles.size(); i++) {
					cout << i + 1 << " - ";
					for (unsigned int j = 0; j < clavesPosibles.at(i).descripcion.size(); j++) {
						cout << clavesPosibles.at(i).descripcion.at(j);
					}
					cout << endl;
				}

				while (eligio != 0 && eligio > clavesPosibles.size()) {
					cout << "Elija una clave para intentar desencriptar el archivo: ";
					cin >> eligio;
				}
				cout << endl;
				if (eligio != 0) {
					string clave;
					for (unsigned int j = 0; j < clavesPosibles.at(eligio - 1).descripcion.size(); j++) {
						clave += clavesPosibles.at(eligio - 1).descripcion.at(j);
					}
					Vigenere* vigenere = new Vigenere(clave);
					string path = vigenere->generarArchivoDesencriptado(pathDesencriptacion, opcion-1);
					delete vigenere;
					string moverArchivo = "mv " + path + " " + Configuracion::getInstancia()->getPathAtaqueKasiski();
					system(moverArchivo.c_str());
					cout << "El archivo desencriptado con la clave elegida se encuentra en: " << Configuracion::getInstancia()->getPathAtaqueKasiski() << endl;
					cout << "Presione una tecla para continuar..." << endl;
					getchar();
				}
				delete kasiski;
			} else {
				cout << "No existe el reporte encriptado para atacar  " << endl;
			}
			encriptado.close();
			getchar();
		}
	}
}

void InterfazAdministrador::menuReportes() {
	Configuracion* config = Configuracion::getInstancia();
	bool fin = false;
	bool resultado;
	int opcion = 0;
	while (!fin) {
		system("clear");

		cout << "Menu Reportes: " << endl;
		cout << "      1- Reporte por Distrito " << endl;
		cout << "      2- Reporte por Lista" << endl;
		cout << "      3- Reporte por Eleccion" << endl;
		cout << "      4- Volver" << endl;
		cout << "Elija la opcion: ";
		cin >> opcion;
		cout << endl;

		switch (opcion) {
		case (1):
			resultado = this->menuReportePorDistrito();
			break;
		case (2):
			resultado = this->menuReportePorLista();
			break;
		case (3):
			resultado = this->menuReportePorEleccion();
			break;
		case (4):
			opcion = 0;
			fin = true;
			break;
		default: {
			cout << "Opcion Incorrecta! Presione cualquier tecla para volver al Menu" << endl;
			getchar();
			opcion = 0;
			break;
		}
		}
		if (opcion != 0) {
			cout << endl;
			if (resultado) {
				cout << "El reporte se genero correctamente, se encuentra en la carpeta : " << config->getPathReportes() << endl;
				string opcionEncripta;
				//Para encriptar se utliza Vigenere
				cout << "Desea encriptar el archivo? (S/N)";
				cin >> opcionEncripta;
				if (Utils::aMinuscula(opcionEncripta) == "s") {
					string claveParaEncriptar;
					cout << "Ingrese la clave para la Encriptacion: ";
					cin >> claveParaEncriptar;
					Vigenere* vigenere = new Vigenere(claveParaEncriptar);
					Configuracion* config = Configuracion::getInstancia();
					string path = config->getPathReportes();
					switch (opcion) {
					case (1):
						path += "reportePorDistrito.txt";
						break;
					case (2):
						path += "reportePorLista.txt";
						break;
					case (3):
						path += "reportePorEleccion.txt";
						break;
					}
					vigenere->generarArchivoEncriptado(path, opcion);
					string opcionDesencripta;
					//Para desencriptar se utliza Vigenere
					cout << "Ahora! Desea desencriptar el archivo recientemente Encriptado? (S/N)";
					cin >> opcionDesencripta;
					if (Utils::aMinuscula(opcionDesencripta) == "s") {
						Configuracion* config = Configuracion::getInstancia();
						string pathDesencriptacion = config->getPathEncriptado();
						switch (opcion) {
						case (1):
							pathDesencriptacion += "reportePorDistritoEncriptado.txt";
							break;
						case (2):
							pathDesencriptacion += "reportePorListaEncriptado.txt";
							break;
						case (3):
							pathDesencriptacion += "reportePorEleccionEncriptado.txt";
							break;
						}
						vigenere->generarArchivoDesencriptado(pathDesencriptacion, opcion);
					}
					delete vigenere;
				}
				system("clear");
				string abrir = "s";
				cout << "Desea abrir el archivo de Reporte? (S/N) :";
				cin >> abrir;
				abrir = Utils::aMinuscula(abrir);
				string pathRepo = "";
				if (abrir == "s") {
					switch (opcion) {
					case (1): {
						pathRepo = "chmod 755 " + config->getPathReportes() + "reportePorDistrito.txt";
						system(pathRepo.c_str());
						pathRepo = "gedit " + config->getPathReportes() + "reportePorDistrito.txt";
						system(pathRepo.c_str());
						break;
					}
					case (2): {
						pathRepo = "chmod 755 " + config->getPathReportes() + "reportePorLista.txt";
						system(pathRepo.c_str());
						pathRepo = "gedit " + config->getPathReportes() + "reportePorLista.txt";
						system(pathRepo.c_str());
						break;
					}
					case (3): {
						pathRepo = "chmod 755 " + config->getPathReportes() + "reportePorEleccion.txt";
						system(pathRepo.c_str());
						pathRepo = "gedit " + config->getPathReportes() + "reportePorEleccion.txt";
						system(pathRepo.c_str());
						break;
					}
					}
				}
				getchar();
			} else {
				cout << "No existen datos para realizar el reporte " << endl;
				getchar();
			}
		}

	}
}

bool InterfazAdministrador::menuReportePorDistrito() {

	ManejadorConteo* manejadorConteo = new ManejadorConteo();
	string fecha = "";
	string distrito = "";
	cout << endl;
	cout << "Ingrese la FECHA de la eleccion: ";
	cin >> fecha;
	cin.ignore(numeric_limits<streamsize>::max(), '\n');

	cout << endl << "Ingrese el nombre del DISTRITO : ";
	getline(cin, distrito);

	bool resultado = manejadorConteo->reportePorDistrito(distrito, fecha);

	delete manejadorConteo;

	return resultado;
}

bool InterfazAdministrador::menuReportePorEleccion() {

	ManejadorConteo* manejadorConteo = new ManejadorConteo();
	string fecha = "";
	string cargo = "";
	cout << endl;
	cout << "Ingrese la FECHA de la eleccion: ";
	cin >> fecha;
	cin.ignore(numeric_limits<streamsize>::max(), '\n');

	cout << endl << "Ingrese el nombre del CARGO : ";
	getline(cin, cargo);

	bool resultado = manejadorConteo->reportePorEleccion(cargo, fecha);

	delete manejadorConteo;

	return resultado;

}

bool InterfazAdministrador::menuReportePorLista() {

	ManejadorConteo* manejadorConteo = new ManejadorConteo();
	string fecha = "";
	string cargo = "";
	string nombreLista = "";
	cout << endl;
	cout << "Ingrese la FECHA de la eleccion: ";
	cin >> fecha;
	cin.ignore(numeric_limits<streamsize>::max(), '\n');

	cout << endl << "Ingrese el nombre del CARGO : ";
	getline(cin, cargo);

	cout << endl << "Ingrese el nombre de la LISTA : ";
	getline(cin, nombreLista);

	bool resultado = manejadorConteo->reportePorLista(cargo, fecha, nombreLista);

	delete manejadorConteo;

	return resultado;

}
void InterfazAdministrador::menuLogs() {

	system("clear");
	Configuracion* config = Configuracion::getInstancia();
	cout << endl;
	cout << " El archivo de Logs se encuentra en la carpeta:" << config->getPathReportes() << endl;
	string abrir = "s";
	cout << "Desea abrir el archivo? (S/N) :";
	cin >> abrir;
	abrir = Utils::aMinuscula(abrir);
	if (abrir == "s") {
		system("chmod 755 ../TPVotoElectronico/Reportes/log.txt ");
		system("gedit ../TPVotoElectronico/Reportes/log.txt");
	}
	cout << " Presione enter para volver al menu " << endl;
	cin.ignore();
	getchar();
}

void InterfazAdministrador::altaMasivaDatos() {
	system("clear");
	cout << "Iniciando alta masiva de datos" << endl;

	IAbm* entidad = new DistritoABM();
	llamadoAltaMasiva(entidad, "distritos");

	entidad = new AdministradorABM();
	llamadoAltaMasiva(entidad, "administradores");

	entidad = new CargoABM();
	llamadoAltaMasiva(entidad, "cargos");

	entidad = new VotanteABM();
	llamadoAltaMasiva(entidad, "votantes");

	entidad = new EleccionABM();
	llamadoAltaMasiva(entidad, "elecciones");

	entidad = new ListaABM();
	llamadoAltaMasiva(entidad, "listas");

	entidad = new CandidatoABM();
	llamadoAltaMasiva(entidad, "candidatos");

	cout << " Presione enter para volver al menu " << endl;
	getchar();

}

void InterfazAdministrador::llamadoAltaMasiva(IAbm* entidad, string nombreEntidad) {
	entidad->altaMasiva();
	cout << "alta de " << nombreEntidad << "..." << endl;
	delete entidad;
}

#include "../Accesorios/VotantesAutomaticos.h"
using namespace Accesorios;

void InterfazAdministrador::menuVotantesAutomaticos() {

	unsigned int cantidadDeVotacionesAutomaticas = 0;
	unsigned int votacionesEfectuadas = 0;

	system("clear");

	cout << "Menu de Votaciones Automáticas" << endl;
	cout << "Ingrese la CANTIDAD de votaciones a realizar (0 si quiere que hacer votar a todos): ";
	cin >> cantidadDeVotacionesAutomaticas;
	cin.ignore(numeric_limits<streamsize>::max(), '\n');

	VotantesAutomaticos* votantesAutomaticos = new VotantesAutomaticos();

	votacionesEfectuadas = votantesAutomaticos->generarVotacionesAutomaticas(cantidadDeVotacionesAutomaticas);

	delete votantesAutomaticos;

	cout << "Votaciones terminadas. Se han efectuado " << votacionesEfectuadas << " votaciones" << endl;
	cout << " Presione enter para volver al menu " << endl;
	getchar();

}

bool InterfazAdministrador::validarUsuarioYContraseniaAdmin(string usuario, string contrasenia) {
	bool validar = false;
	ManejadorAdministrador* manejadorAdministrador = new ManejadorAdministrador();
	Administrador* administrador = manejadorAdministrador->recuperar(usuario);
	if (administrador != NULL) {
		validar = administrador->validarContrasenia(contrasenia);
		if (validar) {
			delete administrador;
		}
	}
	delete manejadorAdministrador;
	return validar;
}

void InterfazAdministrador::menuEncriptarArchivo() {

	InterfazEncriptacion* interfazEncriptacion = new InterfazEncriptacion();
	interfazEncriptacion->mostrarMenuParaEncriptar();
	delete interfazEncriptacion;
}

void InterfazAdministrador::menuDesencriptarArchivo() {

	InterfazEncriptacion* interfazEncriptacion = new InterfazEncriptacion();
	interfazEncriptacion->mostrarMenuParaDesencriptar(this->usuario);
	delete interfazEncriptacion;
}

void InterfazAdministrador::menuAtaqueRSA() {

	InterfazEncriptacion* interfazEncriptacion = new InterfazEncriptacion();
	interfazEncriptacion->mostrarMenuParaRomperRSA();
	delete interfazEncriptacion;
}

void InterfazAdministrador::menuVigenere() {

	bool fin = false;

	while (!fin) {
		system("clear");
		int opcionAdm = 0;
		cout << "Menu Vigenere: " << endl;
		cout << "      1- Encriptar Reporte" << endl;
		cout << "      2- Desencriptar Reporte" << endl;
		cout << "      3- Volver" << endl;
		cout << endl;

		cout << "Elija la opcion: ";
		cin >> opcionAdm;
		cin.ignore();
		cout << endl;
		InterfazEncriptacion* interfazEncriptacion = new InterfazEncriptacion();
		switch (opcionAdm) {
		case (1):
			interfazEncriptacion->mostrarMenuEncriptarVigenere();
			break;
		case (2):
			interfazEncriptacion->mostrarMenuDesencriptarVigenere();
			break;
		case (3):
			fin = true;
			break;
		default: {
			cout << "Opcion Incorrecta! Presione cualquier tecla para volver al Menu" << endl;
			cin.ignore();
			getchar();
		}
		}
		delete interfazEncriptacion;

	}

}

InterfazAdministrador::~InterfazAdministrador() {

}
